// Copyright (C) 2022 Linlexiao
#include "yaku.h"

#include <QDebug>

#define MENZENYAKU \
    if (!handSet.flag.testFlag(HandFlag::MENZEN)) return 0
#define KUISAGARIYAKU(x) \
    int value = x;       \
    if (!handSet.flag.testFlag(HandFlag::MENZEN)) value--;

Yaku::Yaku() = default;

int MenzenTsumo::test(HandSet handSet) {
    if (handSet.flag.testFlag(HandFlag::MENZEN) &&
        handSet.flag.testFlag(HandFlag::TSUMO)) {
        return 1;
    }
    return 0;
}

int TanYao::test(HandSet handSet) {
    for (auto b : handSet.blocks) {
        if (b.consistYao()) {
            return 0;
        }
    }
    if (handSet.pair.getPai()[0].isYao()) return 0;
    return 1;
}

int YakuhaiFieldEast::test(HandSet handSet) {
    if (handSet.flag.testFlag(FIELD_EAST)) {
        for (auto b : handSet.blocks) {
            if (b.paiType == ZI && b.num == 1) {
                return 1;
            }
        }
    }
    return 0;
}
int YakuhaiFieldSouth::test(HandSet handSet) {
    if (handSet.flag.testFlag(FIELD_SOUTH)) {
        for (auto b : handSet.blocks) {
            if (b.paiType == ZI && b.num == 2) {
                return 1;
            }
        }
    }
    return 0;
}
int YakuhaiFieldWest::test(HandSet handSet) {
    if (handSet.flag.testFlag(FIELD_WEST)) {
        for (auto b : handSet.blocks) {
            if (b.paiType == ZI && b.num == 3) {
                return 1;
            }
        }
    }
    return 0;
}
int YakuhaiFieldNorth::test(HandSet handSet) {
    if (handSet.flag.testFlag(FIELD_NORTH)) {
        for (auto b : handSet.blocks) {
            if (b.paiType == ZI && b.num == 4) {
                return 1;
            }
        }
    }
    return 0;
}

int YakuhaiSeatEast::test(HandSet handSet) {
    if (handSet.flag.testFlag(SEAT_EAST)) {
        for (auto b : handSet.blocks) {
            if (b.paiType == ZI && b.num == 1) {
                return 1;
            }
        }
    }
    return 0;
}
int YakuhaiSeatSouth::test(HandSet handSet) {
    if (handSet.flag.testFlag(SEAT_SOUTH)) {
        for (auto b : handSet.blocks) {
            if (b.paiType == ZI && b.num == 2) {
                return 1;
            }
        }
    }
    return 0;
}
int YakuhaiSeatWest::test(HandSet handSet) {
    if (handSet.flag.testFlag(SEAT_WEST)) {
        for (auto b : handSet.blocks) {
            if (b.paiType == ZI && b.num == 3) {
                return 1;
            }
        }
    }
    return 0;
}
int YakuhaiSeatNorth::test(HandSet handSet) {
    if (handSet.flag.testFlag(SEAT_NORTH)) {
        for (auto b : handSet.blocks) {
            if (b.paiType == ZI && b.num == 4) {
                return 1;
            }
        }
    }
    return 0;
}

int YakuhaiHako::test(HandSet handSet) {
    for (auto b : handSet.blocks) {
        if (b.paiType == ZI && b.num == 5) {
            return 1;
        }
    }
    return 0;
}
int YakuhaiHatsu::test(HandSet handSet) {
    for (auto b : handSet.blocks) {
        if (b.paiType == ZI && b.num == 6) {
            return 1;
        }
    }
    return 0;
}
int YakuhaiCyuu::test(HandSet handSet) {
    for (auto b : handSet.blocks) {
        if (b.paiType == ZI && b.num == 7) {
            return 1;
        }
    }
    return 0;
}

int ChanKan::test(HandSet handSet) {
    if (handSet.flag.testFlag(HandFlag::CHANKAN)) {
        return 1;
    }
    return 0;
}

int RinshanKaihou::test(HandSet handSet) {
    if (handSet.flag.testFlag(HandFlag::RINNSHANN_KAIHOU)) {
        return 1;
    }
    return 0;
}

int HaiteiRaoyue::test(HandSet handSet) {
    if (handSet.flag.testFlag(HandFlag::HAITEI_RAOYUE)) {
        return 1;
    }
    return 0;
}

int HouteiRaoyui::test(HandSet handSet) {
    if (handSet.flag.testFlag(HandFlag::HOUTEI_RAOYUI)) {
        return 1;
    }
    return 0;
}

int Riichi::test(HandSet handSet) {
    MENZENYAKU;
    if (handSet.flag.testFlag(HandFlag::RIICHI)) {
        return 1;
    }
    return 0;
}

int Iipeikou::test(HandSet handSet) {
    MENZENYAKU;
    bool found = false;  //是否找到了相同的两个顺子
    Block foundBlock(TRIPLET, ZI, -1, false, 0);
    for (int i = 0; i < 4; i++) {
        for (int j = i + 1; j < 4; j++) {
            Block &a = handSet.blocks[i];
            Block &b = handSet.blocks[j];
            if (a.blockType == BlockType::SEQUENCE && a == b) {
                if (!found) {  // 第一次找到
                    found = true;
                    foundBlock = a;
                } else {  //第二次找到相同的
                    // 如果这次找到的与第一次找到的不一样，那么是两杯口，不与一杯口复合
                    if (!(a == foundBlock)) {
                        return 0;  //两杯口
                    }
                }
            }
        }
    }
    return (int)found;
}

int Pinfu::test(HandSet handSet) {
    MENZENYAKU;
    // 雀头不是役牌
    if (handSet.pair.getPai()[0].isYakuhai(handSet.flag)) return 0;
    // 全部是顺子
    for (auto b : handSet.blocks) {
        if (b.blockType != BlockType::SEQUENCE) {
            return 0;
        }
    }
    // 两面听牌
    if (handSet.type != MachiType::LIANG_MIAN) return 0;
    return 1;
}

int Ippatsu::test(HandSet handSet) {
    MENZENYAKU;
    if (handSet.flag.testFlag(HandFlag::IPPATSU)) {
        return 1;
    }
    return 0;
}
int Dora::test(HandSet handSet) {
    int cnt = 0;
    auto &dora = handSet.dora;
    for (auto b : handSet.blocks) {
        auto pai = b.getPai();

        //进行双重循环 找到宝牌
        for (auto p1 : dora) {
            for (auto p2 : pai) {
                if (p1.next() == p2) {
                    cnt++;
                }
            }
        }
    }
    //雀头中宝牌
    for (auto p1 : dora) {
        if (p1.next() == handSet.pair.getPai()[0]) cnt += 2;
    }
    return cnt;
}
int Ura::test(HandSet handSet) {
    // if(! (handSet.flag.testFlag(RIICHI)))return 0;
    // 这里不做判断是否立直 只要提供了里宝牌 就进行判断
    int cnt = 0;
    auto &ura = handSet.ura;
    for (auto b : handSet.blocks) {
        auto pai = b.getPai();
        for (auto p1 : ura) {
            for (auto p2 : pai) {
                if (p1.next() == p2) {
                    cnt++;
                }
            }
        }
    }
    //雀头中宝牌
    for (auto p1 : ura) {
        if (p1.next() == handSet.pair.getPai()[0]) cnt += 2;
    }
    return cnt;
}
int AkaDora::test(HandSet handSet) {
    int cnt = 0;
    for (auto b : handSet.blocks) {
        cnt += b.redCount;
    }
    cnt += handSet.pair.redCount;
    return cnt;
}

int Toitoi::test(HandSet handSet) {
    for (auto b : handSet.blocks) {
        if (b.blockType == BlockType::SEQUENCE) {
            return 0;
        }
    }
    return 2;
}

int Sanankou::test(HandSet handSet) {
    int cnt = 0;  //暗刻的数量
    for (auto b : handSet.blocks) {
        if (b.blockType != BlockType::SEQUENCE && !b.isOpen) {
            cnt++;
        }
    }
    if (cnt == 3) return 2;
    return 0;
}

int SanshokuDoukou::test(HandSet handSet) {
    int cnt[10] = {0};  //用3个bit表示三种花色是否有此数字的刻子
    for (auto b : handSet.blocks) {
        if (b.blockType != BlockType::SEQUENCE) {
            cnt[b.num] |= (1 << b.paiType);
            if (cnt[b.num] == 7)
                return 2;  //用3个bit表示三种花色是否有此数字的刻子
        }
    }
    return 0;
}

int Sankantsu::test(HandSet handSet) {
    int cnt = 0;  // 杠子的数量
    for (auto b : handSet.blocks) {
        if (b.blockType == BlockType::QUAD) {
            cnt++;
        }
    }
    if (cnt == 3) return 2;
    return 0;
}

int Shousangen::test(HandSet handSet) {
    int cnt = 0;
    for (auto b : handSet.blocks) {
        if (b.paiType == PaiType::ZI && 5 <= b.num && b.num <= 7) {
            cnt++;  // 是三元牌
        }
    }
    if (cnt == 2 && handSet.pair.paiType == PaiType::ZI &&
        5 <= handSet.pair.num && handSet.pair.num <= 7) {
        return 2;
    }
    return 0;
}

int Honroutou::test(HandSet handSet) {
    bool haveZi = false;
    for (auto b : handSet.blocks) {
        if (b.blockType == BlockType::SEQUENCE || !b.getPai()[0].isYao()) {
            return 0;
        }
        if (b.paiType == ZI) haveZi = true;
    }
    if (handSet.pair.paiType == ZI) haveZi = true;
    if (handSet.pair.getPai()[0].isYao() && haveZi) return 2;
    return 0;
}

int DoubleRiichi::test(HandSet handSet) {
    MENZENYAKU;
    if (handSet.flag.testFlag(HandFlag::DOUBLE_RIICHI)) {
        return 2;
    }
    return 0;
}

int SanshokuDoujun::test(HandSet handSet) {
    KUISAGARIYAKU(2);
    int cnt[10] = {};  //用3个bit表示三种花色是否有此数字的顺子
    for (auto b : handSet.blocks) {
        if (b.blockType == BlockType::SEQUENCE) {
            cnt[b.num] |= (1 << b.paiType);
            if (cnt[b.num] == 7) return value;  // 0b111 找到了
        }
    }
    return 0;
}

int Ikkitsuukan::test(HandSet handSet) {
    KUISAGARIYAKU(2);
    int cnt[5] = {};  //三个bit表示 三种花色 是否有123；456；789

    for (auto b : handSet.blocks) {
        if (b.blockType != BlockType::SEQUENCE) continue;
        if (b.num == 1) {
            cnt[(int)b.paiType] |= 1;
            if (cnt[(int)b.paiType] == 7) return value;
        }
        if (b.num == 4) {
            cnt[(int)b.paiType] |= 2;
            if (cnt[(int)b.paiType] == 7) return value;
        }
        if (b.num == 7) {
            cnt[(int)b.paiType] |= 4;
            if (cnt[(int)b.paiType] == 7) return value;
        }
    }
    return 0;
}

int Chantaiyao::test(HandSet handSet) {
    KUISAGARIYAKU(2);

    bool haveJi = false;       //与纯全带幺九不复合
    bool haveSquence = false;  //与混老头不复合
    for (auto b : handSet.blocks) {
        if (b.blockType == SEQUENCE) {
            haveSquence = true;
        } else {
            if (b.paiType == PaiType::ZI) {
                haveJi = true;
            }
        }
        if (!b.consistYao()) return 0;
    }
    if (handSet.pair.paiType == PaiType::ZI) haveJi = true;
    if (!handSet.pair.consistYao()) return 0;

    if (!haveJi || !haveSquence) return 0;
    return value;
}

int Junchantaiyao::test(HandSet handSet) {
    KUISAGARIYAKU(3);

    bool haveJi = false;
    bool haveSquence = false;  //与混老头不复合
    for (auto b : handSet.blocks) {
        if (b.blockType == SEQUENCE) {
            haveSquence = true;
        } else {
            if (b.paiType == PaiType::ZI) {
                haveJi = true;
            }
        }
        if (!b.consistYao()) return 0;
    }
    if (handSet.pair.paiType == PaiType::ZI) haveJi = true;
    if (!handSet.pair.consistYao()) return 0;

    if (haveJi || !haveSquence) return 0;
    return value;
}
int Honiisou::test(HandSet handSet) {
    KUISAGARIYAKU(3);
    int contain[4] = {0};
    for (auto b : handSet.blocks) {
        contain[b.paiType] = 1;
    }
    contain[handSet.pair.paiType] = 1;

    int x = contain[MAN] + contain[SUO] + contain[PIN];
    if (x == 1 && contain[ZI]) return value;  // 必须有字
    return 0;
}

int Ryanpeikou::test(HandSet handSet) {
    MENZENYAKU;
    bool found = false;  //是否找到了相同的两个顺子
    Block foundBlock(TRIPLET, ZI, -1, false, 0);
    for (int i = 0; i < 4; i++) {
        for (int j = i + 1; j < 4; j++) {
            Block &a = handSet.blocks[i];
            Block &b = handSet.blocks[j];
            if (a.blockType == BlockType::SEQUENCE && a == b) {
                if (!found) {
                    found = true;
                    foundBlock = a;
                } else {
                    if (!(a == foundBlock)) {
                        return 3;  // 此时一定两杯口
                    }
                }
            }
        }
    }
    return 0;
}

int Chiniisou::test(HandSet handSet) {
    KUISAGARIYAKU(6);
    int contain[4] = {0};
    for (auto b : handSet.blocks) {
        contain[b.paiType] = 1;
    }
    contain[handSet.pair.paiType] = 1;

    int x = contain[MAN] + contain[SUO] + contain[PIN];
    if (x == 1 && !contain[ZI]) return value;
    return 0;
}

int Daisangen::test(HandSet handSet) {
    int cnt = 0;
    for (auto b : handSet.blocks) {
        if (b.paiType == PaiType::ZI && 5 <= b.num && b.num <= 7) {
            cnt++;  //是三元牌
        }
    }
    if (cnt == 3) return 1;
    return 0;
}

int Suuankou::test(HandSet handSet) {
    MENZENYAKU;
    int cnt = 0;  //暗刻的数量
    for (auto b : handSet.blocks) {
        if (b.blockType != BlockType::SEQUENCE && !b.isOpen) {
            cnt++;
        }
    }
    if (cnt == 4 && !(handSet.agariPai == handSet.pair.getPai()[0])) return 1;
    return 0;
}
int SuuankouTanki::test(HandSet handSet) {
    MENZENYAKU;
    int cnt = 0;  //暗刻的数量
    for (auto b : handSet.blocks) {
        if (b.blockType != BlockType::SEQUENCE && !b.isOpen) {
            cnt++;
        }
    }
    //    qDebug()<<handSet.pair.getPai()[0].num;
    //    qDebug()<<handSet.agariPai.num;
    if (cnt == 4 && handSet.agariPai == handSet.pair.getPai()[0]) return 2;
    return 0;
}

int Shousuushi::test(HandSet handSet) {
    int cnt = 0;
    for (auto b : handSet.blocks) {
        if (b.paiType == PaiType::ZI && 1 <= b.num && b.num <= 4) {
            cnt++;
        }
    }
    if (cnt == 3 && handSet.pair.paiType == PaiType::ZI &&
        1 <= handSet.pair.num && handSet.pair.num <= 4) {
        return 1;
    }
    return 0;
}

int Daisuushi::test(HandSet handSet) {
    int cnt = 0;
    for (auto b : handSet.blocks) {
        if (b.paiType == PaiType::ZI && 1 <= b.num && b.num <= 4) {
            cnt++;
        }
    }
    if (cnt == 4) return 2;
    return 0;
}

int Tsuuiisou::test(HandSet handSet) {
    for (auto b : handSet.blocks) {
        if (b.paiType != PaiType::ZI) {
            return 0;
        }
    }
    if (handSet.pair.paiType != ZI) {
        return 0;
    }
    return 1;
}

int Ryuuiisou::test(HandSet handSet) {
    for (auto b : handSet.blocks) {
        for (auto p : b.getPai()) {
            if (!p.isRyu()) return 0;
        }
    }
    for (auto p : handSet.pair.getPai()) {
        if (!p.isRyu()) return 0;
    }
    return 1;
}

int Chinroutou::test(HandSet handSet) {
    bool haveZi = false;
    for (auto b : handSet.blocks) {
        if (b.blockType == BlockType::SEQUENCE || !b.getPai()[0].isYao()) {
            return 0;
        }
        if (b.paiType == ZI) haveZi = true;
    }
    if (handSet.pair.paiType == ZI) haveZi = true;
    if (handSet.pair.getPai()[0].isYao() && !haveZi) return 1;
    return 0;
}

int ChuurenPoutou::test(HandSet handSet) {
    MENZENYAKU;
    if (!Chiniisou().test(handSet)) return 0;  // 首先清一色（便于后续的处理）
    int cnt[10] = {0};
    int needNum[10] = {0, 3, 1, 1, 1, 1, 1, 1, 1, 3};  // 每个数字 需要的数量
    for (auto b : handSet.blocks) {
        if (b.blockType == QUAD) return 0;
        for (auto p : b.getPai()) {
            cnt[p.num]++;
        }
    }
    for (auto p : handSet.pair.getPai()) {
        cnt[p.num]++;
    }
    int mulNum = -1;
    for (int i = 1; i <= 9; i++) {
        if (cnt[i] < needNum[i] || cnt[i] > needNum[i] + 1) return 0;
        if (cnt[i] == needNum[i] + 1) {
            mulNum = i;  // 多出来的那个牌
        }
    }
    if (mulNum != handSet.agariPai.num) return 1;  // 多出来的那个牌不能是和了牌
    return 0;
}

int JunseiChuurenPoutou::test(HandSet handSet) {
    MENZENYAKU;
    if (!Chiniisou().test(handSet)) return 0;
    int cnt[10] = {0};
    int needNum[10] = {0, 3, 1, 1, 1, 1, 1, 1, 1, 3};
    for (auto b : handSet.blocks) {
        if (b.blockType == QUAD) return 0;
        for (auto p : b.getPai()) {
            cnt[p.num]++;
        }
    }
    for (auto p : handSet.pair.getPai()) {
        cnt[p.num]++;
    }
    int mulNum = -1;
    for (int i = 1; i <= 9; i++) {
        if (cnt[i] < needNum[i] || cnt[i] > needNum[i] + 1) return 0;
        if (cnt[i] == needNum[i] + 1) {
            mulNum = i;
        }
    }
    if (mulNum == handSet.agariPai.num) return 2;
    return 0;
}

int Suukantsu::test(HandSet handSet) {
    for (auto b : handSet.blocks) {
        if (b.blockType != QUAD) return 0;
    }
    return 1;
}

int Tenhou::test(HandSet handSet) {
    MENZENYAKU;
    if (handSet.flag.testFlag(HandFlag::TENHOU)) {
        return 1;
    }
    return 0;
}

int Chiihou::test(HandSet handSet) {
    MENZENYAKU;
    if (handSet.flag.testFlag(HandFlag::CHIIHOU)) {
        return 1;
    }
    return 0;
}
